
// Copyright (c) 2009 Mohannad Alharthi (mohannad.harthi@gmail.com)
// All rights reserved.
// This source code is licensed under the BSD license, which can be found in
// the LICENSE.txt file.

// A new AST implementation

#ifndef INCLUDE_CCOMPX_SRC_AST_H__
#define INCLUDE_CCOMPX_SRC_AST_H__

#include <string>
#include <vector>

#include "symbol_table.h"
#include "misc.h"

class AstNode {
 public:
   virtual ~AstNode() { }
   //virtual std::string toString() = 0;
   //virtual std::string generate() = 0;
   //virtual std::string dump() = 0;
};

class Declaration;
class Function;
class Expression;

// The root node
class TranslationUnit : public AstNode {
public:
  std::vector<Declaration*> declarations_;
  std::vector<Function*> functions_;

  //std::string dump() {
  //  typedef std::vector<Declaration*>::iterator DeclsIter;
  //  DeclsIter it;

  //  for (DeclIter it = declarations_.begin(); it != declarations_.end(); it++)
  //    
  //}
};

// For variables
class Declaration : public AstNode {
 public:
  DataTypeSpec* _type;
  bool _is_ptr;
  std::string identifier_;
  SymbolTable* symbol_table_;
};

class BlockStatement;

class Function : public AstNode {
 public:
  //DataTypeSpec* return_type_;
  //std::string identitfier_;
  //std::vector<std::pair<DataTypeSpec, std::string>> params_list_;
  BlockStatement* body_;
  //int locals_size;
  FunctionSymbol* symbol_;
};

class Statement : public AstNode {
};

class ExprStmt : public Statement {
 public:
  ExprStmt(Expression* expr)
    : expr_(expr) {
  }

  Expression* expr_;
};

typedef Statement NullStatement;

class BlockStatement : public Statement {
 public:
  std::vector<Statement*> statements_;
  SymbolTable* symbol_table_;
};

class Expression;

class IfStatement : public Statement {
 public:
  Expression* condition_;
  Statement* body_;
};

class IfElseStatement : public IfStatement {
 public:
  Statement* else_body_;
};

class ForStatement : public Statement {
 public:
  Statement* stmt1_;
  Statement* stmt2_;
  Statement* stmt3_;
  Statement* body_;
};

class WhileStatement : public Statement {
 public:
  Expression* condition_;
  Statement* body_;
};

class DoStatement : public WhileStatement {
 public:
   //BlockStatement* body_;
};

class Expression : public AstNode {
 public:
   //Expression(DataTypeSpec* spec)
   //  : data_type_(spec) {
   //}

   DataTypeSpec* data_type_;
};

class BinaryOp : public Expression {
 public:
  BinaryOp(TokenCode op, Expression* left, Expression* right)
    : operation_(op),
      left_operand_(left),
      right_operand_(right) {
  }

  TokenCode operation_;
  Expression* left_operand_;
  Expression* right_operand_;
};

class UnaryOp : public Expression {
 public:
   TokenCode operation_;
   Expression* operand_;
};

class VarOperand : public Expression {
 public:
  Symbol* symbol_;
};

class ArrayOperand : public VarOperand {
 public:
  ArrayOperand() { }
  ArrayOperand(Expression* index)
    : index_(index) {
  }

  Expression* index_;
};

template<typename ValTy>
class Literal : public Expression {
 public:
  Literal(/*DataTypeSpec* type_spec,*/ DataType data_type, ValTy literal_value)
    : // type_spec_(type_spec),
      data_type_(data_type),
      literal_value_(literal_value) {
  }

  DataType data_type_;
  //DataTypeSpec* type_spec_;
  ValTy literal_value_;
};

class StaticData : public Expression {
 public:
  StaticData() {
    label_name_ = format("__data__%d", 0/*counter_++*/);
  }

  virtual ~StaticData() { }
  //virtual std::string GenerateData() = 0;
  //virtual int Length() = 0;

  std::string label_name() {
    return label_name_;
  }

  //static int counter_;
  // The label name of the pointer to the static data in its section
  std::string label_name_;
};

//int StaticData::counter_ = 0;

class StaticNumericData : public StaticData {
 public:
  StaticNumericData(int n)
    : number_(n) {
  }

  int number() {
    return number_;
  }
  int length() {
    return 4;
  }

  std::string generateData();

 private:
  int number_;
};

class StaticString : public StaticData {
 public:
  StaticString(const std::string& str)
    : data_(str) {
  }

  std::string data() {
    return data_;
  }
  int length() {
    return data_.length() + 1;
  }

  std::string generateData();

 private:
   std::string data_;
};

class StaticNumericArray : public StaticData {
 public:
   StaticNumericArray(DataType type, std::vector<int>* values)
    : values_(values),
      data_type_(type) {
  }

  std::string generateData();

  int length() {
    return values_->size();
  }

 private:
  std::vector<int>* values_;
  DataType data_type_;
};

#endif // INCLUDE_CCOMPX_SRC_AST_H__
